/**
 * @class 恒星云-古尔德带
 * @author DuskyHuang 圣子
 * @description 是包含太阳系上一级系统，在太阳系周围约3000光年范围内的猎户座悬臂内，包含星座的大多数可见恒星。
*/

import { Component, _decorator, instantiate, Node, MeshRenderer } from 'cc';
import { core } from 'cfw';
import { ConstGroup, LAYER_BG_3D, Res, StarSpectrum } from 'const';
import { createNodeAt, setLayer } from 'helpers';
import { UIProxy, constStars, cosmos } from 'proxies';
import { StarPrecise } from '../stellar/star-precise';
import { SunPrecise } from '../stellar/sun-precise';
import { CultureQuad } from '../stellar/culture-quad';
import { attenuate } from 'algorithms';
const { ccclass, property } = _decorator;

@ccclass('cocosmos.StellarGouldBelt')
export class StellarGouldBelt extends Component {

    @property(SunPrecise) public sun: SunPrecise = null;

    public get configs(): Record<cst, constellationConfig> { return this._configs; }
    public get constStars(): Map<cst, Record<alphabet, StarPrecise>> { return this._constStars; }
    public get stars(): StarPrecise[] { return this._preciseStars; }
    public getStar(cst: cst, ab: alphabet): StarPrecise {
        if (this._constStars.has(cst)) {
            return this._constStars.get(cst)[ab] ??
                this._stars.getChildByName(cst + '-' + ab).getComponent(StarPrecise) ?? null;
        } else return null;
    }

    protected onLoad(): void {
        this._init()._buildConstStars();
    }

    protected update(): void {
        this._stars.active = constStars.showStars;
        this._cultures.active = constStars.showConstCults;
    }

    private _init(): this {
        this._configs = core.res.getConfig(Res.Configs.CONSTELLATION_STARS);
        this._stars = createNodeAt("Stars", LAYER_BG_3D, this.node);
        this._cultures = createNodeAt("Cultures", LAYER_BG_3D, this.node);
        return this;
    }

    protected start(): void {
        this.sun.setSpectrum(StarSpectrum.G, StarSpectrum.K, 0.4);
        this.sun.setNames('太阳', 'Sun');
        this.sun.visible = false;
    }

    protected lateUpdate(): void {
        this._attenuateSun();
    }

    private _buildConstStars(): void {
        const Star = core.res.getPrefab(Res.Prefabs.STAR_PRECISE);
        const Culture = core.res.getPrefab(Res.Prefabs.CULTURE_QUAD);
        for (const key in this._configs) {
            const cst = key as cst;
            const config: constellationConfig = this._configs[cst];
            // if (this._checkSkip(config)) continue;
            const record = {};
            // 星座恒星
            this._constStars.set(cst, record);
            const { stars } = config;
            let nearest: lightyear = DEEP_DIST / 10;
            stars.forEach((line: starLine) => {
                const node = setLayer(instantiate(Star), LAYER_BG_3D);
                const star = node.getComponent(StarPrecise);
                try {
                    if (star.loadConfigLine(line, config)) {
                        node.parent = this._stars;
                        if (!!record[star.config.ab]) console.warn("dupli star", cst + '-' + star.config.ab);
                        record[star.config.ab] = star;
                        if (!star.placeholder) {
                            nearest = Math.min(nearest, star.config.dist);
                        }
                    } else console.warn("star load failed for:", line);
                } catch (e) {
                    console.warn("star load error for:", line);
                }
            });
            // 星座形象
            const { culture } = config;
            if (culture) {
                const node = setLayer(instantiate(Culture), LAYER_BG_3D);
                node.parent = this._cultures;
                const culture = node.getComponent(CultureQuad).loadConfig(config, nearest);
                culture.node.active = false;
            }
        }
        this._preciseStars = this._stars.getComponentsInChildren(StarPrecise);
    }

    private _attenuateSun(): void {
        const { pow10 } = cosmos;
        if (pow10 >= FROM && pow10 <= TO) {
            this.sun.visible = true;
            this.sun.setAlpha(attenuate(pow10, SUN_PRECISE_ATT), attenuate(pow10, SUN_LABEL_ATT));
            this.sun.setScale(Math.lerp(NEAR, FAR, (pow10 - FROM) / SPAN));
        } else this.sun.visible = false;
    }

    /**
     * @deprecated
     * 只用于配置数据时分布检查，正式发布不适用
    */
    private _checkSkip(config: constellationConfig): boolean {
        // if (BUILD) return false;
        if (group >= 0 && !(config.group & group)) return true;
        if (notEmptyArr(only) && !only.contains(config.cst)) return true;
        return false;
    }

    private _configs: Record<cst, constellationConfig>;
    private _constStars = new Map<cst, Record<string, StarPrecise>>();
    private _stars: Node;
    private _cultures: Node;
    private _preciseStars: StarPrecise[];
}
const FROM = -3, TO = 3.5, SPAN = TO - FROM;
const FAR = 0.02, NEAR = 0.2;
const SUN_PRECISE_ATT: attenuation = [FROM, FROM + 1, TO - 1, TO];
const SUN_LABEL_ATT: attenuation = [FROM + 1.5, FROM + 2, TO - 1, TO];
const { DEEP_DIST } = UIProxy;
const group: ConstGroup = ConstGroup.ALL;
const only = [];

// ZODIAC(1)
// const only: cst[] = ['Ari', 'Tau', 'Gem', 'Cnc', 'Leo', 'Vir', 'Lib', 'Sco', 'Sgr', 'Cap', 'Aqr', 'Psc', 'Oph'];

// URSA(2)
// const only: cst[] = ['Boo', 'Cam', 'CVn', 'Com', 'CrB', 'Dra', 'LMi', 'Lyn', 'UMa', 'UMi'];

// HERCULES
// const only: cst[] = ['Aql', 'Ara', 'Cen', 'Crv', 'Crt', 'Cru', 'Cyg', 'Her', 'Hya', 'Lup', 'Lyr', 'Sge', 'Sct', 'Ser', 'Sex', 'TrA', 'Vul'].concat(['Tau', 'Oph']) as cst[];

// PERSEUS
// const only: cst[] = ['And', 'Aur', 'Cas', 'Cep', 'Cet', 'Lac', 'Peg', 'Per', 'Tri'].concat(['Tau']) as cst[];

// ORION
// const only: cst[] = ['CMa', 'CMi', 'Lep', 'Mon', 'Ori'];

// OCEANIC
// const only: cst[] = ['Car', 'Col', 'Del', 'Equ', 'Eri', 'PsA', 'Pup', 'Pyx', 'Vel'].concat(['Cet']) as cst[];

// BAYER
// const only: cst[] = ['Aps', 'Cha', 'Dor', 'Gru', 'Hyi', 'Mus', 'Pav', 'Phe', 'Tuc', 'Vol'].concat([]) as cst[];

// LACAILLE
// const only: cst[] = ['Ant', 'Cae', 'Cir', 'For', 'Nor', 'Hor', 'Men', 'Mic', 'Oct', 'Pic', 'Ret', 'Scl', 'Tel'];